#include <assert.h>
#include <galite/garandom.h>

#ifndef _ga_genome_h_
#define _ga_genome_h_

class GAGenome;

typedef float (*Evaluator)(GAGenome &);
typedef void  (*Initializer)(GAGenome &);
typedef int   (*Mutator)(GAGenome &, float);
typedef int   (*SexualCrossover)(const GAGenome&, const GAGenome&, 
			         GAGenome*, GAGenome*);
class GAGenome {

protected:
  bool _alive;		
  float _fitness;
  bool _evaluated;	
  Evaluator eval;
  Mutator mutr;			
  Initializer init;	
  SexualCrossover sexcross;	
  GARandom *randObj;

public:
  
  GAGenome(Initializer i=0, Mutator m=0);

  GAGenome(const GAGenome&);

  GAGenome & operator=(const GAGenome & arg) {
		copy(arg); 
		return *this;
		}

  virtual ~GAGenome(){}

  virtual GAGenome* clone() const=0;

  virtual int getId()const =0;

  void setRandomObj(GARandom *obj)
	{
	randObj = obj;
	}

  void setAlive() {
		_alive = true;
		}

  void setDead() {
		_alive = false;
		}

  bool isAlive() {
		return _alive;
		}

  virtual void copy(const GAGenome &);

  virtual int equal(const GAGenome &) const = 0;

public:

  float evaluate(bool flag = false);

  float evaluate(float val)
	{
	 _evaluated = true;
	 return _fitness = val;	
	}

  Evaluator evaluator() const {
		return eval;
		}

  Evaluator evaluator(Evaluator f) { 
		_evaluated=false; 
		return(eval=f); 
		}

  void invalidate() {
		_evaluated = false;
		}

  void initialize() {
		_evaluated=false; 
		(*init)(*this);
		}

  Initializer initializer() const {
		return init;
		}

  Initializer initializer(Initializer op){
		return (init=op);
		}

  int mutate(float p) { 
	return((*mutr)(*this,p)); 
	}

  void cross(const GAGenome& partner, GAGenome *daugh, GAGenome *son) {
	sexcross(*this, partner, daugh, son);
	}

  Mutator mutator() const {
	return mutr;
	}

  Mutator mutator(Mutator op) {
	return (mutr=op);
	}

  SexualCrossover crossover(SexualCrossover f) { return sexcross = f; }
  SexualCrossover sexual() const { return sexcross; }

};

#endif
